package ic.doc.co2nudge.client.widgets;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import ic.doc.co2nudge.client.utils.DataServiceFactory;
import ic.doc.co2nudge.client.utils.Utils;
import ic.doc.co2nudge.client.utils.events.DataEvent;
import ic.doc.co2nudge.client.utils.events.DataLoadedEventHandler;
import ic.doc.co2nudge.shared.model.TransportType;
import ic.doc.co2nudge.shared.model.Trip;
import ic.doc.co2nudge.shared.model.TripOption;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.event.MapRightClickHandler;
import com.google.gwt.maps.client.geocode.DirectionResults;
import com.google.gwt.maps.client.geocode.Directions;
import com.google.gwt.maps.client.geocode.DirectionsCallback;
import com.google.gwt.maps.client.geocode.Geocoder;
import com.google.gwt.maps.client.geocode.LatLngCallback;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Overlay;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class NewTripBuildPanel extends Composite {
	
	@UiField DockLayoutPanel 	pnlMain;
	@UiField VerticalPanel 		pnlDistanceAndTripOptions;
	@UiField FlexTable			tblDistnaceAndOptions;
	
	VerticalPanel 				pnlOptionsLabels;
	VerticalPanel 				pnlOptionsValues;
	
	@UiField Label lblTripName;
	@UiField Label lblDate;
	@UiField Label lblNumOfPeople;
	@UiField Label lblStatus;
	
	Label lblDistanceValue;
	
//	@UiField Label lblBudgetType;
//	@UiField Label lblAmount;
	
	@UiField TextBox txtFrom;
	@UiField TextBox txtTo;
	@UiField TextBox txtDate;
	@UiField TextBox txtTripName;
	@UiField TextBox txtNumOfPeople;

//	@UiField ListBox lstNumOfPeople;

	@UiField Button btnGenerateTripOptions;
	@UiField Button btnSaveTrip;
	@UiField Button btnMap;

	private Trip trip;
	private List<TripOption> generatedOptions;
	
	private Geocoder geocoder=new Geocoder();
	
	private LatLng fromPoint;
	private LatLng toPoint;
	private Double distance;
	
	private static NewTripBuildPanelUiBinder uiBinder = GWT
			.create(NewTripBuildPanelUiBinder.class);

	interface NewTripBuildPanelUiBinder extends
			UiBinder<Widget, NewTripBuildPanel> {
	}

	public NewTripBuildPanel() {
		
		initWidget(uiBinder.createAndBindUi(this));	
		setUpTrip();
	}
	
	private void setUpTrip() {
		
		lblDistanceValue=new Label();
		tblDistnaceAndOptions.setWidget(0, 1, lblDistanceValue);
		
		tblDistnaceAndOptions.addStyleName("optionstable");
		lblDistanceValue.addStyleName("distanceValueLabel");
		tblDistnaceAndOptions.setText(0, 0, "Distance");
		tblDistnaceAndOptions.setText(1, 0, "Available options");
		tblDistnaceAndOptions.getFlexCellFormatter()
			.setColSpan(1, 0, 2);
		
		pnlOptionsLabels=new VerticalPanel();
		pnlOptionsValues=new VerticalPanel();
		
		tblDistnaceAndOptions.setWidget(2, 0, pnlOptionsLabels);
		tblDistnaceAndOptions.setWidget(2, 1, pnlOptionsValues);
		
		//handlers
		txtDate.addKeyPressHandler(Utils.getDateKeyboardAdapter());
		txtNumOfPeople.addKeyPressHandler(Utils.getOnlyNumbersKeyboardAdapter());
	}
	
//	private void generateTripOptions(Double distance){
//		List<TransportType> trTypes=DataServiceFactory
//			.getDataService().getTransportTypes(callback)
//	}
		
//		geocoder.getLatLng(fromAddress, new LatLngCallback(){
//
//			@Override
//			public void onFailure() {
//				// TODO Auto-generated method stub
//				lblDistanceValue.setText("Failed - N/A - From Point not found");
//			}
//
//			@Override
//			public void onSuccess(LatLng point) {
//				// TODO Auto-generated method stub
//			
//				if (fromPoint==null){
//					lblDistanceValue.setText("N/A - From Point not found");
//					return;
//				}
//					
//				fromPoint=point;
//				geocoder.getLatLng(toAddress, new LatLngCallback(){
//
//					@Override
//					public void onFailure() {
//						// TODO Auto-generated method stub
//					}
//
//					@Override
//					public void onSuccess(LatLng point) {
//						
//						if (toPoint==null){
//							lblDistanceValue.setText("N/A - To Point not found");
//							return;
//						}
//							
//						toPoint=point;	
//						Double distance=(Double)fromPoint
//							.distanceFrom( toPoint, 6378137);
//					}
//				});
//			}
//		});
	
	@UiHandler("btnMap")
	protected void clickMap(ClickEvent e) {
		
		final PopupPanel pp=new PopupPanel();
		HTMLPanel htmlPanel=new HTMLPanel("Google Maps");
		MapWidget mapWidget=new MapWidget();
		VerticalPanel v=new VerticalPanel();
		HorizontalPanel h=new HorizontalPanel();
		
		Button btnApply=new Button("Apply");
		Button btnClose=new Button("Close");
		
		htmlPanel.setWidth("640px");
		htmlPanel.setHeight("420px");
		
		mapWidget.setWidth("600px");
		mapWidget.setHeight("380px");
		
	    LatLng londonCity = LatLng.newInstance(55.378051,-3.435973);

	    mapWidget.setCenter(londonCity);
	    mapWidget.setZoomLevel(2);
	    mapWidget.addControl(new LargeMapControl());
	    
	    mapWidget.setDoubleClickZoom(true);
	    mapWidget.setContinuousZoom(true);
	    mapWidget.setScrollWheelZoomEnabled(true);
	    
	    final Command takeFromHerePoint=new Command(){

			@Override
			public void execute() {
				// TODO Auto-generated method stub
			}
	    };
	    
	    final Command takeToHerePoint=new Command(){

			@Override
			public void execute() {
				// TODO Auto-generated method stub
				
			}
	    };
	    
	    mapWidget.addMapRightClickHandler( new MapRightClickHandler(){

			@Override
			public void onRightClick(MapRightClickEvent e) {
				
				PopupPanel popupPanel=new PopupPanel();
				
				MenuBar popupMenuBar = new MenuBar(true);
				MenuItem fromHereItem = new MenuItem("Get direction from here", 
						true, takeFromHerePoint);
				MenuItem toHereItem = new MenuItem("Get direction to here", 
						true, takeToHerePoint);
				 
				popupPanel.setStyleName("popup");
				fromHereItem.addStyleName("popup-item");
				toHereItem.addStyleName("popup-item");
				 
				popupMenuBar.addItem(fromHereItem);
				popupMenuBar.addItem(toHereItem);

				popupMenuBar.setVisible(true);
				popupPanel.add(popupMenuBar);
			}
	    });
		
	    h.add(btnApply);
	    h.add(btnClose);
		v.add(mapWidget);
		v.add(h);
		
		btnClose.addClickHandler( new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				pp.hide();
			}
		});
		
		htmlPanel.add(v);
		pp.add(htmlPanel);
		
		pp.setTitle("Get a from and to points of your trip");
		pp.setGlassEnabled(true);
		pp.setPopupPosition(100, 100);
		pp.show();
	}
	
	@UiHandler("btnGenerateTripOptions")
	protected void clickGenerateTripOptions(ClickEvent e){
		
		trip=new Trip();
		
		String from = txtFrom.getText().trim();
		String to = txtTo.getText().trim();
		String strNumOfPeople=txtNumOfPeople.getText().trim();
		
		if ((from.length()==0)||(to.length()==0)
				||(strNumOfPeople.length()==0)) {
			return;
		}
		
		int numOfPeople=Integer
			.parseInt( txtNumOfPeople.getText().trim());
		
		if (!from.contains("UK"))
			from+=", UK";
		
		if (!to.contains("UK"))
			to+=", UK";
		
		if ((from.length()==0)
				||(to.length()==0))
			return;
		
		lblDistanceValue.setText("");
		
		DataServiceFactory.addDataLoadedListener( 
				new DataLoadedEventHandler(){
					
					@SuppressWarnings("unchecked")
					@Override
					public void dataLoaded(DataEvent e){
						if (e.isCompletedSuccessfully())
						{
							HashMap<String, Object> tripOptionsData=
								new HashMap<String, Object>();
							
							tripOptionsData=(HashMap<String, Object>)e.getData();
							
							distance=(Double)tripOptionsData
								.get("Distance");
							
							generatedOptions=
								(List<TripOption>)tripOptionsData
									.get("Options");
							
							showTripOptions(generatedOptions);
							
						}else
							Window.alert("error");	
						
						DataServiceFactory.removeDataLoadedListener();
					}
				});
		
		DataServiceFactory.generateTripOptions(from, to, numOfPeople);
	}
	
	private void showTripOptions(List<TripOption> options){
		
		generatedOptions=options;
		pnlOptionsLabels.clear();
		pnlOptionsValues.clear();
		
		ClickHandler btnOptionClickHandler=
			new ClickHandler(){

				@Override
				public void onClick(ClickEvent e) {
					int index=0;

					VerticalPanel p=(VerticalPanel)((RadioButton)e.getSource())
						.getParent();
					index=p.getWidgetIndex((RadioButton)e.getSource());
					
					trip.setChosenCO2Option(generatedOptions.get(index));
				}
		};
		
		for (TripOption opt: options){
			
			double distanceInKm=
				Utils.round( Utils.getDistanceInKm(distance));
			lblDistanceValue.setText( distanceInKm +" km");
			
			String typeName=opt.getTransportType().getName();
			Double rate= Utils.round( opt.getRate());
				
			Label lblOptionLabel=new Label();
			lblOptionLabel.setText(typeName);
			
			RadioButton btnTripOption=
				new RadioButton( "options", 
						rate+" kg");
			
			btnTripOption.addClickHandler(btnOptionClickHandler);
			btnTripOption.addStyleName("tripoptionbutton");
			
			pnlOptionsLabels.add(lblOptionLabel);
			pnlOptionsValues.add(btnTripOption);
		}
		
		pnlDistanceAndTripOptions.setVisible(true);
	}
	
	@UiHandler("btnSaveTrip")
	protected void clickSaveTrip(ClickEvent e) {
		
//		List<String> errors=ValidationHelper.validateTrip(trip);
//		if (errors.size()!=0)
//			return;
		
		try{
			
			String tripName=txtTripName.getText();
			String strTripDate=txtDate.getText();
			
			DateTimeFormat format= DateTimeFormat
				.getFormat("dd/MM/yyyy");
			Date tripDate=format.parse( strTripDate);

			int numOfPeople=Integer.parseInt( txtNumOfPeople.getText());
			
			String from=txtFrom.getText().trim();
			String to=txtTo.getText().trim();
			
			trip.setName( tripName);
			trip.setDate( tripDate);
			trip.setDistance( distance);
			trip.setNumOfPeople( numOfPeople);
			trip.setFrom( from);
			trip.setTo( to);
			
			findMinAndMaxTripOption( trip);
			DataServiceFactory.addDataLoadedListener(
					new DataLoadedEventHandler(){
						
						@Override
						public void dataLoaded(DataEvent e){
							
							String strResult="";
							
							if (e.isCompletedSuccessfully()){
								strResult="Trip saved";
								clearUI();
							}else
								strResult="An error occured while saving a trip";
							showStatus(strResult);		
						}
					});
			
			DataServiceFactory.saveTrip( trip);
		}
		catch(Exception ex3){
			Window.alert(ex3.toString());
		}
	}
	
	private void clearUI(){
		txtFrom.setText("");
		txtTo.setText("");
		txtNumOfPeople.setText("");
		txtDate.setText("");
		txtTripName.setText("");
		
		trip=null;
		
		pnlDistanceAndTripOptions.setVisible(false);
		
	}
	
	private void findMinAndMaxTripOption(Trip trip) {

		TripOption[] options=generatedOptions
			.toArray( new TripOption[0]);
		
		Arrays.sort( options, new Comparator<TripOption>() {
			@Override
			public int compare(TripOption opt1, TripOption opt2) {				
				return opt1.getRate()>opt2.getRate()?1:0;
			}
		});
		
		trip.setMinCO2Option(options[0]);
		trip.setMaxCO2Option(options[options.length-1]);
	}

	private void showStatus(String status){
		
		final String statusMsg=status;
		lblStatus.setText(statusMsg);
		lblStatus.setVisible(true);
		
		Timer timer=new Timer(){
			public void run(){
				lblStatus.setVisible(false);
			}
		};
		timer.schedule(4000);
	}
}